#!/bin/bash
###SHELLPACK preamble pgbench-bench 13.3
install-depends gnuplot

ROLE=`whoami`
DBUSER=nobody
EFFECTIVE_CACHESIZE=$((756*1048576))
SHARED_BUFFERS=$((32*1048576))
WORK_MEM=$((32*1048576))
MAX_TIME=
MAX_TRANSACTIONS=
READONLY_ARG=
SCALE_FACTOR=1
VACUUM_ARG=-n
RUN_CACHE_COLD=no
MIN_THREADS=1

. $SHELLPACK_INCLUDE/monitors.sh

###SHELLPACK parseargBegin
###SHELLPACK parseargInstall
###SHELLPACK parseargParam --effective-cachesize EFFECTIVE_CACHESIZE
###SHELLPACK parseargParam --shared-buffers      SHARED_BUFFERS
###SHELLPACK parseargParam --work-mem            WORK_MEM

###SHELLPACK parseargParam --min-threads	 MIN_THREADS
###SHELLPACK parseargParam --max-threads         MAX_THREADS
###SHELLPACK parseargParam --scale-factor        SCALE_FACTOR
###SHELLPACK parseargParam --max-time            MAX_TIME
###SHELLPACK parseargParam --max-transactions    MAX_TRANSACTIONS
###SHELLPACK parseargYes   --read-only           READONLY
###SHELLPACK parseargYes   --cache-cold          RUN_CACHE_COLD
###SHELLPACK parseargEnd
###SHELLPACK monitor_hooks

# Always scrub sources as the benchmark in question does not properly
# reinitialise itself if the data partitions gets scrubbed
###SHELLPACK init_only_start
	rm -rf $SHELLPACK_SOURCES/postgres*
	$SHELLPACK_TOPLEVEL/shellpack_src/src/refresh.sh postgresbuild
###SHELLPACK init_only_continue

echo Copying database configuration
export PGHOST=127.0.0.1
export PGPORT=5432
export PATH=$SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/bin:$PATH
export LD_LIBRARY_PATH=$SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/lib
PSQL=$SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/bin/psql
RUNDBUSER="su -s /bin/bash $DBUSER -c"

MID=$(((MEMTOTAL_BYTES-EFFECTIVE_CACHESIZE-SHARED_BUFFERS)/2))
if [ $MID -lt 0 ]; then
	MID=0
fi

if [ "$MAX_TRANSACTIONS" = "auto" ]; then
	if [ "$READONLY" = "yes" ]; then
		CEILING=20000000
		WEIGHT_MAINMEMORY=2
		WEIGHT_DISK=600
	else
		CEILING=2000000
		WEIGHT_MAINMEMORY=2
		WEIGHT_DISK=300
	fi
	FLOOR=15000
	WORKLOAD_SIZE=$((SCALE_FACTOR*15*1048576+30*1048576))
	cat > /tmp/points <<EOF
$SHARED_BUFFERS          $CEILING
$EFFECTIVE_CACHESIZE     $((CEILING/WEIGHT_MAINMEMORY))
$((EFFECTIVE_CACHESIZE+SHARED_BUFFERS))  $((CEILING/WEIGHT_MAINMEMORY/8))
$((MEMTOTAL_BYTES-MID))	 $((CEILING/WEIGHT_MAINMEMORY/32))
$MEMTOTAL_BYTES 	 $((CEILING/WEIGHT_MAINMEMORY/16))
$((MEMTOTAL_BYTES*3/2))  $((CEILING/WEIGHT_DISK*4))
$((MEMTOTAL_BYTES*3)) $((CEILING/WEIGHT_DISK))
$((MEMTOTAL_BYTES*4)) $((CEILING/WEIGHT_DISK*48))
$((MEMTOTAL_BYTES*8)) $((CEILING/WEIGHT_DISK*96))
EOF

	cat > /tmp/gnuplot.script <<EOF
set terminal dumb
set table "/tmp/coordinates"
plot '/tmp/points' smooth cspline
EOF
	cat /tmp/gnuplot.script | gnuplot > /dev/null

        MAX_TRANSACTIONS=`awk "{ if (\\$1 >= \$WORKLOAD_SIZE) print \\$2 }" /tmp/coordinates | head -1`
	MAX_TRANSACTIONS=`perl -e "print int $MAX_TRANSACTIONS"`
	if [ "$MAX_TRANSACTIONS" = "" ]; then
		MAX_TRANSACTIONS=$FLOOR
	fi
	if [ $MAX_TRANSACTIONS -lt $FLOOR ]; then
		MAX_TRANSACTIONS=$FLOOR
	fi
	mv /tmp/points $LOGDIR_RESULTS/pgbench-auto-points
	mv /tmp/coordinates $LOGDIR_RESULTS/pgbench-auto-coordinates
fi

if [ "$PGBENCH_DEBUG_AUTO_TRANSACTIONS" = "yes" ]; then
	cat $LOGDIR_RESULTS/pgbench-auto-points
	echo MAX_TRANSACTIONS = $MAX_TRANSACTIONS
	exit $SHELLPACK_SUCCESS
fi

if [ "$READONLY" = "yes" ]; then
	READONLY_ARG=-S
fi

###SHELLPACK init_only_start
	echo Starting database for first time as part of init
	$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --start \
		--effective_cachesize $EFFECTIVE_CACHESIZE \
		--shared_buffers $SHARED_BUFFERS \
		--work_mem $WORK_MEM \
		-v ${VERSION} || die Failed to get a usable postgres installation

	echo Stopping database to finish init
	$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --stop

	echo pgbench installed only as requested
	exit $SHELLPACK_SUCCESS
###SHELLPACK init_only_end

echo Running pgbench
cp $SHELLPACK_DATA/pgdata/postgresql.conf $LOGDIR_RESULTS
echo o maximum $MAX_THREADS threads
echo o scale factor: $SCALE_FACTOR 
echo $SCALE_FACTOR > $LOGDIR_RESULTS/pgbench-scale
LAST_THREAD=0

FIRST_TIME=yes

###SHELLPACK threads_huge_stride_begin $MIN_THREADS $MAX_THREADS
	# Do not repeat iterations due to thread count
	if [ $NR_THREADS -eq $LAST_THREAD ]; then
		continue
	fi

	PGBENCH_THREADS=$NUMNODES
	if [ $NR_THREADS -lt $NUMNODES ]; then
		PGBENCH_THREADS=1
	else
		NR_THREADS=$(((NR_THREADS+NUMNODES-1)&~(NUMNODES-1)))
	fi
	LAST_THREAD=$NR_THREADS

	if [ "$DATABASE_INIT_ONCE" != "yes" -o "$FIRST_TIME" = "yes" ]; then
		echo Starting database for initialisation
		mmtests_activity init
		$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --start \
			--effective_cachesize $EFFECTIVE_CACHESIZE \
			--shared_buffers $SHARED_BUFFERS \
			--work_mem $WORK_MEM \
			-v ${VERSION} || die Failed to get a usable postgres installation

		echo Preparing database
		$RUNDBUSER "$PSQL template1 -c 'DROP DATABASE pgbench;'"
		$RUNDBUSER "$PSQL template1 -c 'DROP ROLE $ROLE;'"
		$RUNDBUSER "$PSQL template1 -c 'CREATE DATABASE pgbench;'" || die Failed to setup database
		$RUNDBUSER "$PSQL template1 -c 'CREATE ROLE $ROLE with LOGIN;'" || die Failed to create $ROLE role

		echo Initialising database for pgbench: Scale factor $SCALE_FACTOR
		$TIME_CMD -o $LOGDIR_RESULTS/load-${NR_THREADS}.time \
			pgbench -h $PGHOST -p $PGPORT \
				-i $VACUUM_ARG -s $SCALE_FACTOR pgbench \
				> $LOGDIR_RESULTS/load-${NR_THREADS}.log 2>&1
	fi

	if [ "$DATABASE_INIT_ONCE" = "yes" -a "$FIRST_TIME" = "yes" ]; then
		mmtests_activity warmup

		# Pick a warm-up time based on the database size.
		# Every scale factor is roughly 30M so warm for
		# 1 minute per 100M of database size. The minimum
		# time is MAX_TIME if configured up to a maximum
		# of 30 minutes.
		WARM_TIME=$((SCALE_FACTOR/100))
		if [ $WARM_TIME -eq 0 ]; then
			WARM_TIME=1
		fi
		if [ "$MAX_TIME" != "" ]; then
			if [ $WARM_TIME -lt $((MAX_TIME/60)) ]; then
				WARM_TIME=$((MAX_TIME/60))
			fi
		fi
		if [ $WARM_TIME -gt 30 ]; then
			WARM_FACTOR=30
		fi

		echo Warming up database for $WARM_TIME minutes
		pgbench -v -h $PGHOST -p $PGPORT -r \
			$VACUUM_ARG $READONLY_ARG -c $MAX_THREADS -j $MAX_THREADS \
			-T $((60*WARM_TIME)) pgbench
	fi

	FIRST_TIME=no

	if [ "$RUN_CACHE_COLD" = "yes" ]; then
		echo Stopping database to drop cache
		$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --stop

		echo Dumping cache to run database cache cold as requested
		echo 3 > /proc/sys/vm/drop_caches

		# Starting database
		echo Starting database cache cold
		$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --start \
			--effective_cachesize $EFFECTIVE_CACHESIZE \
			--shared_buffers $SHARED_BUFFERS \
			--work_mem $WORK_MEM \
			-v ${VERSION} || die Failed to get a usable postgres installation
	fi

	# Work out max time or max transactions commands
	MAX_TIME_COMMAND=
	MAX_TRANSACTIONS_COMMAND=
	if [ "$MAX_TIME" != "" ]; then
		MAX_TIME_COMMAND="-T $MAX_TIME"
		echo $MAX_TIME > $LOGDIR_RESULTS/pgbench-time
	else
		if [ "$MAX_TRANSACTIONS" != "" ]; then
			MAX_TRANSACTIONS_COMMAND="-t $((MAX_TRANSACTIONS/NR_THREADS))"
		else
			die Specify time or transactions
		fi
		echo $((MAX_TRANSACTIONS/NR_THREADS)) > $LOGDIR_RESULTS/pgbench-nr-transactions-$NR_THREADS
	fi

	monitor_pre_hook $LOGDIR_RESULTS $NR_THREADS
	mmtests_activity $NR_THREADS
	echo o $NR_THREADS/$PGBENCH_MAX_THREADS threads $MAX_TRANSACTIONS transactions
	start_deferred_monitors "$NR_THREADS/$PGBENCH_MAX_THREADS threads $MAX_TRANSACTIONS transactions"
	$TIME_CMD -o $LOGDIR_RESULTS/time-${NR_THREADS} \
		pgbench -v -h $PGHOST -p $PGPORT -r \
			-l --aggregate-interval=1 \
			$VACUUM_ARG $READONLY_ARG -c $NR_THREADS -j $PGBENCH_THREADS \
			$MAX_TRANSACTIONS_COMMAND $MAX_TIME_COMMAND \
			pgbench > $LOGDIR_RESULTS/pgbench-$NR_THREADS.log
	SYSRET=$?
	stop_deferred_monitors
	if [ $SYSRET -ne 0 ]; then
		cat $LOGDIR_RESULTS/pgbench-$NR_THREADS.log
		die pgbench failed to execute
	fi
	for FILE in `ls pgbench_log.*`; do
		mv $FILE $LOGDIR_RESULTS/pgbench-transactions-$NR_THREADS.log
		gzip -f $LOGDIR_RESULTS/pgbench-transactions-$NR_THREADS.log
	done
	monitor_post_hook $LOGDIR_RESULTS $NR_THRADS
###SHELLPACK threads_stride_end

echo Cleaning up and shutting down
$RUNDBUSER "$PSQL template1 -c 'DROP DATABASE pgbench;'"
$RUNDBUSER "$PSQL template1 -c 'DROP ROLE $ROLE;'"
$SHELLPACK_INCLUDE/shellpack-bench-postgresbuild --stop
cp $SHELLPACK_SOURCES/postgresbuild-${VERSION}-installed/logfile $LOGDIR_RESULTS/dblog

echo pgbench successfully completed
exit $SHELLPACK_SUCCESS
